///*
// * Licensed to the Apache Software Foundation (ASF) under one
// * or more contributor license agreements.  See the NOTICE file
// * distributed with this work for additional information
// * regarding copyright ownership.  The ASF licenses this file
// * to you under the Apache License, Version 2.0 (the
// * "License"); you may not use this file except in compliance
// * with the License.  You may obtain a copy of the License at
// *
// *     http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//package my.test.mvstore;
//
//import java.util.ArrayList;
//import java.util.concurrent.Callable;
//import java.util.concurrent.ConcurrentSkipListMap;
//import java.util.concurrent.ConcurrentSkipListSet;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.Future;
//
//import org.h2.mvstore.MVMap;
//import org.h2.mvstore.Page;
//import org.h2.mvstore.type.DataType;
//import org.h2.mvstore.type.ObjectDataType;
//
//public class LockFreeMVMap2<K, V> extends MVMap<K, V> implements Callable<Void> {
//
//    private static Merger merger;
//    static {
//        merger = new Merger();
//        merger.start();
//    }
//
//    public static void stopMerger() {
//        merger.stopMerger();
//    }
//
//    private static class ValueHolder<V> {
//        final V value;
//        //final byte tag;
//
//        ValueHolder(V value, int tag) {
//            this.value = value;
//            //this.tag = (byte) tag;
//        }
//
//        ValueHolder(V value) {
//            this(value, 0);
//        }
//    }
//
//    private volatile ConcurrentSkipListMap<K, V> current = new ConcurrentSkipListMap<K, V>();
//    private volatile ConcurrentSkipListMap<K, ValueHolder<V>> current2 = new ConcurrentSkipListMap<K, ValueHolder<V>>();
//    private volatile ConcurrentSkipListMap<K, V> merging;
//    private volatile ConcurrentSkipListMap<K, ValueHolder<V>> merging2 = new ConcurrentSkipListMap<K, ValueHolder<V>>();
//    private volatile ConcurrentSkipListSet<Object> removed;
//
//    public LockFreeMVMap2(DataType keyType, DataType valueType) {
//        super(keyType, valueType);
//
//        merger.addMap(this);
//    }
//
//    @Override
//    public V put(K key, V value) {
//        current2.put(key, new ValueHolder<V>(value));
//
//        return current.put(key, value);
//    }
//
//    @Override
//    public V get(Object key) {
//        V v = current.get(key);
//        if (v != null)
//            return v;
//
//        ValueHolder<V> vh = current2.get(key);
//        if (vh != null) {
//            if (vh.value == null)
//                return null;
//            return vh.value;
//        }
//
//        if (merging != null) {
//            v = merging.get(key);
//            if (v != null)
//                return v;
//        }
//
//        v = super.get(key);
//        if (v != null && removed.contains(key))
//            return null;
//
//        return v;
//    }
//
//    @SuppressWarnings("unchecked")
//    @Override
//    public V remove(Object key) {
//        V v = current.remove(key);
//        if (v != null)
//            return v;
//
//        ValueHolder<V> vh = current2.remove(key);
//        if (vh != null) {
//            if (vh.value == null)
//                return null;
//
//            return vh.value;
//        }
//
//        if (merging != null) {
//            v = merging.remove(key);
//            if (v != null)
//                return v;
//        }
//
//        v = super.get(key);
//        if (v != null) {
//            removed.add(key);
//
//            current2.put((K) key, new ValueHolder<V>(null));
//        }
//        return v;
//    }
//
//    @Override
//    public Void call() throws Exception {
//        beginMerge();
//        return null;
//    }
//
//    private void beginMerge() {
//        merging = current;
//        current = new ConcurrentSkipListMap<K, V>();
//
//        merging2 = current2;
//        current2 = new ConcurrentSkipListMap<K, ValueHolder<V>>();
//
//        merge();
//
//        merging = null;
//        merging2 = null;
//    }
//
//    private void merge() {
//        beforeWrite();
//
//        long v = writeVersion;
//        Page p;
//        Object key;
//        Object value;
//
//        for (Entry<K, V> e : merging.entrySet()) {
//            p = root.copy(v);
//            key = e.getKey();
//            value = e.getValue();
//            p = splitRootIfNeeded(p, v);
//            put(p, v, key, value);
//            newRoot(p);
//        }
//
//        for (Entry<K, ValueHolder<V>> e : merging2.entrySet()) {
//            key = e.getKey();
//            value = e.getValue().value;
//
//            p = root.copy(v);
//
//            if (value != null) {
//                p = splitRootIfNeeded(p, v);
//                put(p, v, key, value);
//            } else {
//                remove(p, v, key);
//                if (!p.isLeaf() && p.getTotalCount() == 0) {
//                    p.removePage();
//                    //p = Page.createEmpty(this, p.getVersion());
//                }
//            }
//
//            newRoot(p);
//        }
//
//        for (Object k : removed) {
//            p = root.copy(v);
//            remove(p, v, k);
//            if (!p.isLeaf() && p.getTotalCount() == 0) {
//                p.removePage();
//                //p = Page.createEmpty(this, p.getVersion());
//            }
//            newRoot(p);
//
//            removed.remove(k);
//        }
//    }
//
//    public static class Merger extends Thread {
//        private static final ExecutorService executorService = Executors.newCachedThreadPool();
//
//        private volatile boolean isRunning;
//        private final ArrayList<LockFreeMVMap2<?, ?>> maps = new ArrayList<LockFreeMVMap2<?, ?>>();
//        private final ArrayList<Future<Void>> futures = new ArrayList<Future<Void>>();
//
//        public synchronized void addMap(LockFreeMVMap2<?, ?> map) {
//            maps.add(map);
//        }
//
//        public Merger() {
//            super("BTree-Merger");
//        }
//
//        @Override
//        public void run() {
//            isRunning = true;
//            long millis = 5 * 60 * 1000;
//            while (isRunning) {
//                try {
//                    sleep(millis);
//                } catch (InterruptedException e) {
//                    //e.printStackTrace();
//                }
//
//                for (LockFreeMVMap2<?, ?> map : maps) {
//                    futures.add(executorService.submit(map));
//                }
//
//                for (Future<Void> f : futures) {
//                    try {
//                        f.get();
//                    } catch (Exception e) {
//                        //e.printStackTrace();
//                    }
//                }
//
//                futures.clear();
//            }
//        }
//
//        public void stopMerger() {
//            isRunning = false;
//            interrupt();
//            try {
//                join();
//            } catch (InterruptedException e) {
//                //e.printStackTrace();
//            }
//
//            executorService.shutdown();
//        }
//    }
//
//    /**
//     * A builder for this class.
//     *
//     * @param <K> the key type
//     * @param <V> the value type
//     */
//    public static class Builder<K, V> implements MapBuilder<LockFreeMVMap2<K, V>, K, V> {
//
//        protected DataType keyType;
//        protected DataType valueType;
//
//        /**
//         * Create a new builder with the default key and value data types.
//         */
//        public Builder() {
//            // ignore
//        }
//
//        /**
//         * Set the key data type.
//         *
//         * @param keyType the key type
//         * @return this
//         */
//        public Builder<K, V> keyType(DataType keyType) {
//            this.keyType = keyType;
//            return this;
//        }
//
//        /**
//         * Set the key data type.
//         *
//         * @param valueType the key type
//         * @return this
//         */
//        public Builder<K, V> valueType(DataType valueType) {
//            this.valueType = valueType;
//            return this;
//        }
//
//        @Override
//        public LockFreeMVMap2<K, V> create() {
//            if (keyType == null) {
//                keyType = new ObjectDataType();
//            }
//            if (valueType == null) {
//                valueType = new ObjectDataType();
//            }
//            return new LockFreeMVMap2<K, V>(keyType, valueType);
//        }
//    }
//}